package com.pic.mgt.haishin.executer;

import java.io.File;
import java.io.IOException;

import org.springframework.dao.DataAccessException;

import com.pic.mgt.dao.BasicBusinessTargetActionInfoBean;
import com.pic.mgt.executer.TargetFileProcessException;
import com.pic.mgt.file.io.FileBuilder;
import com.pic.mgt.haishin.executer.tar.DeTarFile;
import com.pic.mgt.log.IgxLog;
import com.pic.mgt.monitor.parser.ConfirmtaionFileForTxFileParser;
import com.pic.mgt.utils.FilePathUtils;
import com.pic.mgt.utils.IgxUtils;


final class ByCommonTargetFileProcess extends HaishinTargetFileProcess {
	private String haishinOutboxPublic;	
	private FileBuilder oneLineContentFileBuilder;
	
	private boolean isNeedToDetarToPublicOutbox;
	
	public ByCommonTargetFileProcess(DeTarFile deTarFile) {
		super(deTarFile);
	}
	
	@Override
	protected boolean validateTargetDest(String terminal) {
		
		return terminal.equals(haishinOutboxPublic);
		
	}
	
	@Override
	protected void updateHaishinBusinessMgtDbStatusToFinish()
			throws DataAccessException {
		/*
		 * 覆寫掉父類(HaishinTargetFileProcess)的updateHaishinBusinessMgtDbStatusToFinish() 方法.
		 * 因為在 by common 的 target file 處理中,目標檔案處理完後不算動作做完。還要完成指示檔的建立，
		 * 才算是配信動作的完成。
		 * 因此，在 Asgmt 動作處理完後，才將狀態更新為 BUSINESS_EXECUTING_FINISH
		 */
	}
	
	@Override
	protected void doRedoHaishinBusinessPreprocess() throws TargetFileProcessException {
		// ********************** Log **********************
		IgxLog.messageLog.info(this,
						"Checking common transaction file status for business '{}' in redo mode.",
						super.haishinBusiness.getUnitName());
		// ********************** Log **********************

		// 從資料庫取得該業務先前解 tar 至 public outbox 目錄內的記錄(如果有的話)
		BasicBusinessTargetActionInfoBean basicBusinessTargetActionInfoBean = null;
		try {
			// throws DataAccessException
			basicBusinessTargetActionInfoBean = super.haishinBusinessTargetActionDao.
					findBasicBusinessTargetActionInfoByUnitName(super.haishinBusiness.getUnitName());
		} catch (DataAccessException e1) {
			throw new TargetFileProcessException(
					"Checking common transaction file status for business '" + super.haishinBusiness.getUnitName() + 
					"' occured a database operation error in redo mode.",e1);
		}
		
		if (null == basicBusinessTargetActionInfoBean) {
			// 代表上一次該業務的 target file 解 tar 動作未完成,本次的 redo 是需要做的
			
			this.isNeedToDetarToPublicOutbox = true;
			
			// ********************** Log **********************
			IgxLog.messageLog.warn(this,
							"Common transaction file for business '{}' will be redone since last execution was failed or file doesn't exist.",
							super.haishinBusiness.getUnitName());
			// ********************** Log **********************
		}
		else {
			/*
			 *   代表上一次該業務的 target file 解 tar 動作完成,
			 *    但尚需再確認此交易檔案(包含確認檔)是否正確存在.
			 */
			
			/*
			 * 上一次該業務的 target file 解 tar 動作完成,但要再看其確認檔是否也產生出來並且內容正確,
			 *  若沒產生出來或內容不正確,要再產生確認檔出來.
			 */
			
			// 取得交易檔
			File transactionFile = FilePathUtils.multiPathConcat(
											super.haishinOutboxPahtStr,
											this.haishinOutboxPublic,
											basicBusinessTargetActionInfoBean.getFilename());
			
			if (transactionFile.exists()) {
				// 資料庫中有記錄,且檔案也確實存在,則不需要再做目標檔的解 tar 了.
				
				this.isNeedToDetarToPublicOutbox = false;
				
				// ********************** Log **********************
				IgxLog.messageLog.info(this,
								"Common transaction file for business '{}' will not be redone again since last execution was successful or file already existed correctly.",
								super.haishinBusiness.getUnitName());
				// ********************** Log **********************
				
				
				/*
				 *  雖然交易檔已正確存在(所以不需再做目標檔的解 tar),但要再檢查它的確認檔是否
				 *  存在或者確認檔的內容是否正確, 若有問題則重建確認檔出來.
				 */
				
				
				// 取得交易檔的確認檔
				File confirmationFileForTxFile =
						ConfirmtaionFileForTxFileParser.getConfirmationFile(transactionFile);
				
				// 判斷是否要產生確檔
				try {
					if (!confirmationFileForTxFile.exists()) {
						// 產生 Confirmation File
						generateConfirmationFile(confirmationFileForTxFile,
												 basicBusinessTargetActionInfoBean.getFilesize());
					}
					else {
						// 確認檔存在的話,還要再檢查其內容正不正確 (內容的檔案大於是否等於目標檔案的檔案大小)
						
						long filesizeInConfirmationFileContent =
								IgxUtils.getConfirmationFileContentForFilesize(confirmationFileForTxFile);
						if (filesizeInConfirmationFileContent == 
								basicBusinessTargetActionInfoBean.getFilesize()) {
							// 確認檔正確的被產生出來
						}
						else {
							// 產生 Confirmation File
							generateConfirmationFile(confirmationFileForTxFile,
													 basicBusinessTargetActionInfoBean.getFilesize());
						}
					}
				} catch (IOException e) {
					throw new TargetFileProcessException(
							"Checking common transaction file status for business '" + super.haishinBusiness.getUnitName() + 
							"' occured an I/O error in redo mode.", e);
				}
			}
			else {
				// 資料庫中有紀錄,但檔案已不存在了,要再做目標檔的解 tar 動作
				
				this.isNeedToDetarToPublicOutbox = true;
				
				// ********************** Log **********************
				IgxLog.messageLog.warn(this,
								"Common transaction file for business '{}' will be redone since last execution was failed or file doesn't exist.",
								super.haishinBusiness.getUnitName());
				// ********************** Log **********************
			}
		}
	}
	
	private void generateConfirmationFile(File confirmationFile, long transactionFilesize) throws IOException {
		this.oneLineContentFileBuilder.append(String.valueOf(transactionFilesize));
		this.oneLineContentFileBuilder.buildFile(confirmationFile);
		
		// ********************** Log **********************
		IgxLog.messageLog.warn(this,
						"Re-generating confirmation file '{}' for common transaction file completed since last execution was failed.",
						confirmationFile.getName());
		// ********************** Log **********************
	}
	
	@Override
	protected boolean isFilteredTxFileInRedoMode(String deTarterminal, String deTarFilename) {
		/*
		 *  因為 ByCommon 的 Target File Process,只會解 target file 到 public outbox 一個目錄中.
		 *  所以其實可以不用管 termina ,因為 terminal 將都會是 ex: '000000000'
		 */
		
		
		return !this.isNeedToDetarToPublicOutbox;
	}
	
	@Override
	protected void deTarFinish() {
		// do nothing
	}
	
	// --- getter and setter

	public void setHaishinOutboxPublic(String haishinOutboxPublic) {
		this.haishinOutboxPublic = haishinOutboxPublic;
	}

	public void setOneLineContentFileBuilder(FileBuilder oneLineContentFileBuilder) {
		this.oneLineContentFileBuilder = oneLineContentFileBuilder;
	}
}
